home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Palettes / MiscTableScroll / MiscTableBorder.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-11  |  57.1 KB  |  2,166 lines

  1. //=============================================================================
  2. //
  3. //        Copyright (C) 1995, 1996 by Paul S. McCarthy and Eric Sunshine.
  4. //                Written by Paul S. McCarthy and Eric Sunshine.
  5. //                            All Rights Reserved.
  6. //
  7. //        This notice may not be removed from this source code.
  8. //
  9. //        This object is included in the MiscKit by permission from the authors
  10. //        and its use is governed by the MiscKit license, found in the file
  11. //        "License.rtf" in the MiscKit distribution.    Please refer to that file
  12. //        for a list of all applicable permissions and restrictions.
  13. //        
  14. //=============================================================================
  15. //-----------------------------------------------------------------------------
  16. // MiscTableBorder.cc
  17. //
  18. //        Structure describing border of an MiscTableView.
  19. //
  20. //        NOTE: many of the sub-arrays in an MiscTableBorder are conditional.
  21. //        They are not guaranteed to be allocated for every instance.     They are
  22. //        only allocated when the caller tries to store a value in them.
  23. //
  24. //        FIXME: Optimization: separate slot-offset calculations from
  25. //        resizing calculations.    Many situations only require an offset-
  26. //        update, not a full size recalc.
  27. //
  28. //        FIXME: Optimization: fold sort-direction together with sort-type
  29. //        into a single array.  Encode sort-direction as a single bit.
  30. //
  31. //        FIXME: Optimization, simplification: Do not maintain all arrays in
  32. //        visual order.  Only maintain sizing array (slots[]) in visual order
  33. //        keep all the others in physical order.
  34. //
  35. //-----------------------------------------------------------------------------
  36. //-----------------------------------------------------------------------------
  37. // $Id: MiscTableBorder.cc,v 1.11 96/01/13 23:42:07 zarnuk Exp $
  38. // $Log:        MiscTableBorder.cc,v $
  39. //    Revision 1.11  96/01/13     23:42:07  zarnuk
  40. //    MiscCompareCellFunc -> MiscCompareEntryFunc.
  41. //    
  42. //    Revision 1.10  95/11/12     23:20:03  sunshine
  43. //    Fixed bugs where selection manipulation methods were not checking for valid
  44. //    slot.  Fixes bug where selectedSlot() was returning "random" and possibly
  45. //    out-of-range values.
  46. //    
  47. //    Revision 1.9  95/10/20    00:12:05  sunshine
  48. //    Was including MiscTableScroll.h with "" instead of <>.
  49. //    
  50. //    Revision 1.8  95/10/19    05:37:11  sunshine
  51. //    Column slots are no longer 'springy' by default.
  52. //-----------------------------------------------------------------------------
  53. #ifdef __GNUC__
  54. # pragma implementation
  55. #endif
  56. #include "MiscTableBorder.h"
  57. #include <misckit/MiscTableScroll.h>
  58. #include <misckit/MiscTableCell.h>
  59.  
  60. extern "Objective-C" {
  61. #import <objc/zone.h>
  62. #import <appkit/Cell.h>
  63. #import <appkit/ButtonCell.h>
  64. }
  65.  
  66. extern "C" {
  67. #include <assert.h>
  68. #include <math.h>                // floor()
  69. #include <stdlib.h>
  70. #include <string.h>
  71. }
  72.  
  73. #define MISC_LIMIT_CHECK(LO,HI)\
  74.         do {\
  75.         assert( 0 <= LO );\
  76.         assert( LO <= HI );\
  77.         assert( HI <= MISC_MAX_PIXELS_SIZE );\
  78.         } while(0)
  79.  
  80. #define MISC_RANGE_CHECK(X)        assert( 0 <= X );  assert( X < num_slots )
  81. #define MISC_RANGE_CHECK_1(X)    assert( 0 <= X );  assert( X <= num_slots )
  82.  
  83. #define MISC_ENUM_CHECK(E,N)    assert((unsigned int)(E) <= (unsigned int)(N))
  84.  
  85. #define MISC_SLOT_MEMBER(X,M)    ((slots != 0) ? slots[X].M : def_slot.M)
  86. #define MISC_SET_SLOT_MEMBER(X,N,M)\
  87.         do {\
  88.         needs_recalc = true;\
  89.         if (slots == 0) alloc_slots();\
  90.         slots[X].M = N;\
  91.         } while (0)
  92.  
  93. #define MISC_MAP(M,I)    (((M) != 0) ? (M)[I] : I)
  94.  
  95. #define MISC_DEF_SORT_DIR        MISC_SORT_ASCENDING
  96. #define MISC_DEF_SORT_TYPE        MISC_SORT_STRING_CASE_INSENSITIVE
  97.  
  98. enum MiscShrinkMode
  99.         {
  100.         SPRINGY_ADJ,    // adj_size - size        Springy slots
  101.         SPRINGY_CORE,    // size - min_size        Springy slots
  102.         RIGID_ADJ,        // adj_size - size        Non-springy slots
  103.         RIGID_CORE,        // size - min_size        Non-springy slots
  104.         SPRINGY_MIN,    // min_size - 0            Springy slots
  105.         RIGID_MIN,        // min_size - 0            Non-springy slots
  106.         ZERO_SIZE_SLOT
  107.         };
  108.  
  109. //-----------------------------------------------------------------------------
  110. // get_prototype
  111. //-----------------------------------------------------------------------------
  112. id MiscTableBorder::get_prototype( MiscCoord_V i ) const
  113.     {
  114.     return [owner border:type getDelegateSlotPrototype:visualToPhysical(i)];
  115.     }
  116.  
  117.  
  118. //-----------------------------------------------------------------------------
  119. // get_title
  120. //-----------------------------------------------------------------------------
  121. char const* MiscTableBorder::get_title( MiscCoord_V i ) const
  122.     {
  123.     return [owner border:type getDelegateSlotTitle:visualToPhysical(i)];
  124.     }
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. // setOwner
  129. //-----------------------------------------------------------------------------
  130. void MiscTableBorder::setOwner( MiscTableScroll* x )
  131.     {
  132.     owner = x;
  133.     }
  134.  
  135.  
  136.  
  137. //-----------------------------------------------------------------------------
  138. // shrink_mode
  139. //-----------------------------------------------------------------------------
  140. int MiscTableBorder::shrink_mode( MiscTableSlot& r )
  141.     {
  142.     int x = 0;
  143.     if (r.isSpringy())
  144.         {
  145.         if (r.adj_size > r.size)
  146.             x = (int) SPRINGY_ADJ;
  147.         else if (r.adj_size > r.min_size)
  148.             x = (int) SPRINGY_CORE;
  149.         else if (r.adj_size > 0)
  150.             x = (int) SPRINGY_MIN;
  151.         else
  152.             x = (int) ZERO_SIZE_SLOT;
  153.         }
  154.     else
  155.         {
  156.         if (r.adj_size > r.size)
  157.             x = (int) RIGID_ADJ;
  158.         else if (r.adj_size > r.min_size)
  159.             x = (int) RIGID_CORE;
  160.         else if (r.adj_size > 0)
  161.             x = (int) RIGID_MIN;
  162.         else
  163.             x = (int) ZERO_SIZE_SLOT;
  164.         }
  165.     return x;
  166.     }
  167.  
  168.  
  169. //-----------------------------------------------------------------------------
  170. // global_shrink
  171. //-----------------------------------------------------------------------------
  172. void MiscTableBorder::global_shrink( MiscPixels total_size )
  173.     {
  174.     MiscPixels excess = total_size - max_total_size;
  175.     MiscPixels amt[ (int) RIGID_MIN + 1 ];
  176.     int i;
  177.  
  178.     for (i = 0;     i <= (int) RIGID_MIN;    i++)
  179.         amt[i] = 0;
  180.  
  181.     for (i = 0;     i < num_slots;     i++)
  182.         {
  183.         MiscTableSlot& r = slots[i];
  184.         MiscPixels delta_adj = r.adj_size - r.size;
  185.         MiscPixels delta_core = r.size - r.min_size;
  186.         if (r.isSpringy())
  187.             {
  188.             amt[ SPRINGY_ADJ ]    += delta_adj;
  189.             amt[ SPRINGY_CORE ] += delta_core;
  190.             amt[ SPRINGY_MIN ]    += r.min_size;
  191.             }
  192.         else
  193.             {
  194.             amt[ RIGID_ADJ ]  += delta_adj;
  195.             amt[ RIGID_CORE ] += delta_core;
  196.             amt[ RIGID_MIN ]  += r.min_size;
  197.             }
  198.         }
  199.  
  200.     int mode = 0;
  201.     while (mode <= (int) RIGID_MIN && excess > amt[mode])
  202.         {
  203.         excess -= amt[mode];
  204.         mode++;
  205.         }
  206.  
  207.     assert( mode <= (int) RIGID_MIN );
  208.     assert( excess <= amt[mode] );
  209.     assert( 0 < excess );
  210.     assert( 0 < amt[mode] );
  211.  
  212.     double const scaler = double(excess) / double(amt[mode]);
  213.     MiscPixels adj_sum = 0;
  214.  
  215.     for (i = 0;     i < num_slots;     i++)
  216.         {
  217.         MiscTableSlot& r = slots[i];
  218.         r.offset -= adj_sum;
  219.         MiscPixels const delta_adj    = r.adj_size - r.size;
  220.         MiscPixels const delta_core = r.size - r.min_size;
  221.         MiscPixels const delta_min    = r.min_size;
  222.         MiscPixels adj = 0;
  223.         MiscPixels factor = 0;
  224.         if (r.isSpringy())
  225.             {
  226.             if (mode >    (int) SPRINGY_ADJ)        adj += delta_adj;
  227.             if (mode == (int) SPRINGY_ADJ)        factor = delta_adj;
  228.             if (mode >    (int) SPRINGY_CORE)        adj += delta_core;
  229.             if (mode == (int) SPRINGY_CORE)        factor = delta_core;
  230.             if (mode >    (int) SPRINGY_MIN)        adj += delta_min;
  231.             if (mode == (int) SPRINGY_MIN)        factor = delta_min;
  232.             }
  233.         else
  234.             {
  235.             if (mode >    (int) RIGID_ADJ)        adj += delta_adj;
  236.             if (mode == (int) RIGID_ADJ)        factor = delta_adj;
  237.             if (mode >    (int) RIGID_CORE)        adj += delta_core;
  238.             if (mode == (int) RIGID_CORE)        factor = delta_core;
  239.             if (mode >    (int) RIGID_MIN)        adj += delta_min;
  240.             if (mode == (int) RIGID_MIN)        factor = delta_min;
  241.             }
  242.         adj += (MiscPixels) floor( double(factor) * scaler );
  243.         if (adj > excess)
  244.             adj = excess;
  245.         excess -= adj;
  246.         r.adj_size -= adj;
  247.         adj_sum += adj;
  248.         }
  249.  
  250.     while (excess > 0)
  251.         {
  252.         adj_sum = 0;
  253.         for (i = 0;     i < num_slots;     i++)
  254.             {
  255.             MiscTableSlot& r = slots[i];
  256.             r.offset -= adj_sum;
  257.             if (excess > 0)
  258.                 {
  259.                 int rank = shrink_mode( r );
  260.                 if (rank <= mode)
  261.                     {
  262.                     r.adj_size--;
  263.                     excess--;
  264.                     adj_sum++;
  265.                     }
  266.                 }
  267.             }
  268.         assert( adj_sum > 0 );
  269.         }
  270.     }
  271.  
  272.  
  273.  
  274. //-----------------------------------------------------------------------------
  275. // find_springy_slot
  276. //-----------------------------------------------------------------------------
  277. MiscCoord_V MiscTableBorder::find_springy_slot() const
  278.     {
  279.     assert( num_slots > 0 );
  280.     assert( num_springy > 0 );
  281.     MiscCoord_V const lim = num_slots - 1;
  282.     MiscCoord_V x = 0;
  283.     for ( ;     x < lim;  x++)
  284.         if (slots[x].isSpringy())
  285.             break;
  286.     return x;
  287.     }
  288.  
  289.  
  290. //-----------------------------------------------------------------------------
  291. // global_grow
  292. //-----------------------------------------------------------------------------
  293. void MiscTableBorder::global_grow( MiscPixels total_size )
  294.     {
  295.     MiscPixels deficit = min_total_size - total_size;
  296.     if (num_springy > 0)
  297.         {
  298.         if (num_springy == 1)
  299.             {
  300.             MiscCoord_V x = find_springy_slot();
  301.             slots[x].adj_size += deficit;
  302.             while (++x < num_slots)
  303.                 slots[x].offset += deficit;
  304.             }
  305.         else // (num_springy > 1)
  306.             {
  307.             MiscCoord_V x;
  308.             MiscPixels springy_sum = 0;
  309.             for (x = 0;     x < num_slots;     x++)
  310.                 if (slots[x].isSpringy())
  311.                     springy_sum += slots[x].size;
  312.     
  313.             double scaler = 1;
  314.             if (springy_sum == 0)
  315.                 scaler = 1.0 / double(num_springy);
  316.             else
  317.                 scaler = double(deficit) / double(springy_sum);
  318.     
  319.             MiscPixels adj_sum = 0;
  320.             for (x = 0;     x < num_slots;     x++)
  321.                 {
  322.                 MiscTableSlot& r = slots[x];
  323.                 r.offset += adj_sum;
  324.                 if (r.isSpringy())
  325.                     {
  326.                     MiscPixels adj = (MiscPixels)
  327.                                 floor( double(r.size) * scaler );
  328.                     if (adj > deficit)
  329.                         adj = deficit;
  330.                     deficit -= adj;
  331.                     r.adj_size += adj;
  332.                     adj_sum += adj;
  333.                     }
  334.                 }
  335.     
  336.             while (deficit > 0)
  337.                 {
  338.                 adj_sum = 0;
  339.                 for (x = 0;     x < num_slots;     x++)
  340.                     {
  341.                     MiscTableSlot& r = slots[x];
  342.                     r.offset += adj_sum;
  343.                     if (r.isSpringy() && deficit > 0)
  344.                         {
  345.                         deficit--;
  346.                         r.adj_size++;
  347.                         adj_sum++;
  348.                         }
  349.                     }
  350.                 assert( adj_sum != 0 );
  351.                 }
  352.             }
  353.         }
  354.     }
  355.  
  356.  
  357. //-----------------------------------------------------------------------------
  358. // perform_recalc
  359. //-----------------------------------------------------------------------------
  360. void MiscTableBorder::perform_recalc()
  361.     {
  362.     MISC_LIMIT_CHECK( min_total_size, max_total_size );
  363.  
  364.     int i;
  365.     MiscPixels total_size = 0;
  366.  
  367.     if (slots == 0)
  368.         alloc_slots();
  369.  
  370.     for (i = 0;     i < num_slots;     i++)
  371.         {
  372.         MiscTableSlot& r = slots[i];
  373.         assert( 0 <= r.min_size );
  374.         assert( r.min_size <= r.size );
  375.         assert( r.size <= r.max_size );
  376.         assert( r.max_size <= MISC_MAX_PIXELS_SIZE );
  377.         r.offset = total_size;
  378.         r.adj_size = r.size;
  379.         if (r.isData() && r.adj_size < r.data_size)
  380.             {
  381.             r.adj_size = r.data_size;
  382.             if (r.adj_size > r.max_size)
  383.                 r.adj_size = r.max_size;
  384.             }
  385.         total_size += r.adj_size;
  386.         }
  387.  
  388.     if (total_size < min_total_size)
  389.         global_grow( total_size );
  390.  
  391.     else if (total_size > max_total_size)
  392.         global_shrink( total_size );
  393.     }
  394.  
  395.  
  396. //-----------------------------------------------------------------------------
  397. // do_recalc
  398. //-----------------------------------------------------------------------------
  399. void MiscTableBorder::do_recalc()
  400.     {
  401.     needs_recalc = false;
  402.     if (uniform_size == 0 && num_slots > 0)
  403.         perform_recalc();
  404.     }
  405.  
  406.  
  407. //-----------------------------------------------------------------------------
  408. // recalc_if_needed
  409. //-----------------------------------------------------------------------------
  410. inline void MiscTableBorder::recalc_if_needed()
  411.     {
  412.     if (needs_recalc)
  413.         do_recalc();
  414.     }
  415.  
  416.  
  417. //-----------------------------------------------------------------------------
  418. // recalcOffsets
  419. //-----------------------------------------------------------------------------
  420. void MiscTableBorder::recalcOffsets()
  421.     {
  422.     needs_recalc = true;
  423.     recalc_if_needed();
  424.     }
  425.  
  426.  
  427.  
  428. //-----------------------------------------------------------------------------
  429. // alloc_size
  430. //-----------------------------------------------------------------------------
  431. inline int MiscTableBorder::alloc_size( int rec_size )
  432.     {
  433.     return rec_size * max_slots;
  434.     }
  435.  
  436.  
  437. //-----------------------------------------------------------------------------
  438. // do_alloc
  439. //-----------------------------------------------------------------------------
  440. void* MiscTableBorder::do_alloc( int size )
  441.     {
  442.     return malloc( alloc_size(size) );
  443.     }
  444.  
  445.  
  446.  
  447. //-----------------------------------------------------------------------------
  448. // do_alloc_init
  449. //-----------------------------------------------------------------------------
  450. void* MiscTableBorder::do_alloc_init( int size )
  451.     {
  452.     int const nbytes = alloc_size( size );
  453.     void* const p = malloc( nbytes );
  454.     memset( p, 0, nbytes );
  455.     return p;
  456.     }
  457.  
  458.  
  459.  
  460. //-----------------------------------------------------------------------------
  461. // do_realloc
  462. //-----------------------------------------------------------------------------
  463. void* MiscTableBorder::do_realloc( void* p, int size )
  464.     {
  465.     if (p != 0)
  466.         {
  467.         if (max_slots != 0)
  468.             {
  469.             p = realloc( p, max_slots * size );
  470.             }
  471.         else
  472.             {
  473.             free( p );
  474.             p = 0;
  475.             }
  476.         }
  477.     return p;
  478.     }
  479.  
  480.  
  481. //-----------------------------------------------------------------------------
  482. // do_realloc
  483. //-----------------------------------------------------------------------------
  484. void MiscTableBorder::do_realloc()
  485.     {
  486.     slots  = (MiscTableSlot*) do_realloc( slots, sizeof(*slots) );
  487.     v2p       = (MiscCoord_P*) do_realloc( v2p, sizeof(*v2p) );
  488.     p2v       = (MiscCoord_V*) do_realloc( p2v, sizeof(*p2v) );
  489.     tags   = (int*) do_realloc( tags, sizeof(*tags) );
  490.     titles = (char**) do_realloc( titles, sizeof(*titles) );
  491.     styles = (MiscTableCellStyle*) do_realloc( styles, sizeof(*styles) );
  492.     prototypes = (id*) do_realloc( prototypes, sizeof(*prototypes) );
  493.     sort_funcs = (MiscCompareEntryFunc*)
  494.                         do_realloc( sort_funcs, sizeof(*sort_funcs) );
  495.     sort_dirs = (MiscSortDirection*) do_realloc(sort_dirs,sizeof(*sort_dirs));
  496.     sort_types = (MiscSortType*) do_realloc( sort_types, sizeof(*sort_types) );
  497.     }
  498.  
  499.  
  500. //-----------------------------------------------------------------------------
  501. // freeExtraCapacity
  502. //-----------------------------------------------------------------------------
  503. void MiscTableBorder::freeExtraCapacity()
  504.     {
  505.     if (max_slots > num_slots)
  506.         {
  507.         max_slots = num_slots;
  508.         do_realloc();
  509.         }
  510.     }
  511.  
  512.  
  513. //-----------------------------------------------------------------------------
  514. // setCapacity
  515. //-----------------------------------------------------------------------------
  516. void MiscTableBorder::setCapacity( int x )
  517.     {
  518.     if (max_slots < x)
  519.         {
  520.         max_slots = x;
  521.         do_realloc();
  522.         }
  523.     }
  524.  
  525.  
  526.  
  527. //-----------------------------------------------------------------------------
  528. // empty
  529. //-----------------------------------------------------------------------------
  530. void MiscTableBorder::empty()
  531.     {
  532.     setCount(0);
  533.     selectNone();
  534.     clearCursor();
  535.     }
  536.  
  537.  
  538.  
  539. //-----------------------------------------------------------------------------
  540. // init_slot
  541. //-----------------------------------------------------------------------------
  542. void MiscTableBorder::init_slot( MiscCoord_V x, MiscCoord_P p )
  543.     {
  544.     if (def_slot.isSpringy())
  545.         num_springy++;
  546.  
  547.     if (slots != 0)
  548.         slots[x] = def_slot;
  549.  
  550.     if (tags != 0)
  551.         tags[x] = def_tag;
  552.  
  553.     if (titles != 0)
  554.         titles[x] = 0;
  555.  
  556.     if (styles != 0)
  557.         styles[x] = def_style;
  558.  
  559.     if (prototypes != 0)
  560.         prototypes[x] = 0;
  561.  
  562.     if (sort_funcs != 0)
  563.         sort_funcs[x] = 0;
  564.  
  565.     if (sort_dirs != 0)
  566.         sort_dirs[x] = MISC_DEF_SORT_DIR;
  567.  
  568.     if (sort_types != 0)
  569.         sort_types[x] = MISC_DEF_SORT_TYPE;
  570.  
  571.     if (v2p != 0)
  572.         {
  573.         v2p[x] = p;
  574.         p2v[p] = x;
  575.         }
  576.     }
  577.  
  578.  
  579. //-----------------------------------------------------------------------------
  580. // destroy_slot
  581. //-----------------------------------------------------------------------------
  582. void MiscTableBorder::destroy_slot( MiscCoord_V x )
  583.     {
  584.     if (isSpringy(x))
  585.         num_springy--;
  586.  
  587.     if (titles != 0 && titles[x] != 0)
  588.         free( titles[x] );
  589.  
  590.     if (prototypes != 0 && prototypes[x] != 0)
  591.         [prototypes[x] free];
  592.     }
  593.  
  594.  
  595. //-----------------------------------------------------------------------------
  596. // do_delete
  597. //-----------------------------------------------------------------------------
  598. void MiscTableBorder::do_delete( void* p, int i, int n )
  599.     {
  600.     if (p != 0)
  601.         memmove( p + i * n, p + (i + 1) * n, (num_slots - i) * n );
  602.     }
  603.  
  604.  
  605. //-----------------------------------------------------------------------------
  606. // do_delete
  607. //-----------------------------------------------------------------------------
  608. void MiscTableBorder::do_delete( MiscCoord_V x, MiscCoord_P p )
  609.     {
  610.     if (x < num_slots)
  611.         {
  612.         do_delete( slots, x, sizeof(*slots) );
  613.         do_delete( v2p, x, sizeof(*v2p) );
  614.         do_delete( tags, x, sizeof(*tags) );
  615.         do_delete( titles, x, sizeof(*titles) );
  616.         do_delete( styles, x, sizeof(*styles) );
  617.         do_delete( prototypes, x, sizeof(*prototypes) );
  618.         do_delete( sort_funcs, x, sizeof(*sort_funcs) );
  619.         do_delete( sort_dirs, x, sizeof(*sort_dirs) );
  620.         do_delete( sort_types, x, sizeof(*sort_types) );
  621.         }
  622.     if (p < num_slots)
  623.         do_delete( p2v, p, sizeof(*p2v) );
  624.     }
  625.  
  626.  
  627. //-----------------------------------------------------------------------------
  628. // deleteAt
  629. //-----------------------------------------------------------------------------
  630. void MiscTableBorder::deleteAt( MiscCoord_V x )
  631.     {
  632.     MISC_RANGE_CHECK( x );
  633.  
  634.     selection.shiftDownAt( x );
  635.     if (num_slots <= 1)
  636.         clearCursor();
  637.  
  638.     needs_recalc = true;
  639.  
  640.     MiscCoord_P const p = visualToPhysical(x);
  641.  
  642.     destroy_slot( x );
  643.  
  644.     num_slots--;
  645.     do_delete( x, p );
  646.  
  647.     if (v2p != 0)
  648.         {
  649.         for (int i = 0;     i < num_slots;     i++)
  650.             {
  651.             if (v2p[i] >= p)
  652.                 v2p[i]--;
  653.             if (p2v[i] >= x)
  654.                 p2v[i]--;
  655.             }
  656.         }
  657.  
  658.     }
  659.  
  660.  
  661. //-----------------------------------------------------------------------------
  662. // do_insert
  663. //-----------------------------------------------------------------------------
  664. void MiscTableBorder::do_insert( void* p, int i, int n )
  665.     {
  666.     if (p != 0)
  667.         memmove( p + (i + 1) * n, p + i * n, (num_slots - i) * n );
  668.     }
  669.  
  670.  
  671. //-----------------------------------------------------------------------------
  672. // do_insert
  673. //-----------------------------------------------------------------------------
  674. void MiscTableBorder::do_insert( MiscCoord_V x, MiscCoord_P p )
  675.     {
  676.     if (x < num_slots)
  677.         {
  678.         do_insert( slots, x, sizeof(*slots) );
  679.         do_insert( v2p, x, sizeof(*v2p) );
  680.         do_insert( tags, x, sizeof(*tags) );
  681.         do_insert( titles, x, sizeof(*titles) );
  682.         do_insert( styles, x, sizeof(*styles) );
  683.         do_insert( prototypes, x, sizeof(*prototypes) );
  684.         do_insert( sort_funcs, x, sizeof(*sort_funcs) );
  685.         do_insert( sort_dirs, x, sizeof(*sort_dirs) );
  686.         do_insert( sort_types, x, sizeof(*sort_types) );
  687.         }
  688.  
  689.     if (p < num_slots)
  690.         do_insert( p2v, p, sizeof(*p2v) );
  691.     }
  692.  
  693.  
  694. //-----------------------------------------------------------------------------
  695. // insertAt
  696. //-----------------------------------------------------------------------------
  697. void MiscTableBorder::insertAt( MiscCoord_V x, MiscCoord_P p )
  698.     {
  699.     MISC_RANGE_CHECK_1( x );
  700.  
  701.     needs_recalc = true;
  702.  
  703.     if (num_slots >= max_slots)
  704.         setCapacity( max_slots + 1 );
  705.  
  706.     do_insert( x, p );
  707.  
  708.     if (v2p != 0)
  709.         {
  710.         for (int i = 0;     i < num_slots;     i++)
  711.             {
  712.             if (p2v[i] >= x)
  713.                 p2v[i]++;
  714.             if (v2p[i] >= p)
  715.                 v2p[i]++;
  716.             }
  717.         }
  718.  
  719.     init_slot( x, p );
  720.  
  721.     num_slots++;
  722.  
  723.     selection.shiftUpAt( x );
  724.     if (hasValidCursor() && cursor >= x)
  725.         cursor++;
  726.     }
  727.  
  728.  
  729. //-----------------------------------------------------------------------------
  730. // do_shift
  731. //-----------------------------------------------------------------------------
  732. void MiscTableBorder::do_shift( void* p, int i, int j, int n )
  733.     {
  734.     if (p != 0)
  735.         {
  736.         if (i < j)
  737.             memmove( p + i * n, p + (i + 1) * n, (j - i) * n );
  738.         else
  739.             memmove( p + (j     + 1) * n, p + j * n, (i - j) * n );
  740.         }
  741.     }
  742.  
  743.  
  744. //-----------------------------------------------------------------------------
  745. // do_shift
  746. //-----------------------------------------------------------------------------
  747. void MiscTableBorder::do_shift( MiscCoord_V from, MiscCoord_V to )
  748.     {
  749.     do_shift( slots, from, to, sizeof(*slots) );
  750.     do_shift( v2p, from, to, sizeof(*v2p) );
  751.     do_shift( tags, from, to, sizeof(*tags) );
  752.     do_shift( titles, from, to, sizeof(*titles) );
  753.     do_shift( styles, from, to, sizeof(*styles) );
  754.     do_shift( prototypes, from, to, sizeof(*prototypes) );
  755.     do_shift( sort_funcs, from, to, sizeof(*sort_funcs) );
  756.     do_shift( sort_dirs, from, to, sizeof(*sort_dirs) );
  757.     do_shift( sort_types, from, to, sizeof(*sort_types) );
  758.     }
  759.  
  760.  
  761. //-----------------------------------------------------------------------------
  762. // alloc_vmap
  763. //-----------------------------------------------------------------------------
  764. void MiscTableBorder::alloc_vmap()
  765.     {
  766.     p2v = (MiscCoord_V*) do_alloc( sizeof(*p2v) );
  767.     v2p = (MiscCoord_P*) do_alloc( sizeof(*v2p) );
  768.     for (int i = 0;     i < num_slots;     i++)
  769.         {
  770.         p2v[i] = i;
  771.         v2p[i] = i;
  772.         }
  773.     }
  774.  
  775.  
  776. //-----------------------------------------------------------------------------
  777. // moveFromTo
  778. //-----------------------------------------------------------------------------
  779. void MiscTableBorder::moveFromTo( MiscCoord_V from, MiscCoord_V to )
  780.     {
  781.     MISC_RANGE_CHECK( from ); MISC_RANGE_CHECK( to );
  782.  
  783.     bool const was_cursor = (hasValidCursor() && cursor == from);
  784.     bool const was_selected = selection.contains( from );
  785.     selection.shiftDownAt( from );
  786.  
  787.     needs_recalc = true;
  788.  
  789.     MiscCoord_P const p = visualToPhysical( from );
  790.     MiscTableSlot const tmp_slot = slots ? slots[from] : def_slot;
  791.     int const tmp_tag = (tags ? tags[from] : def_tag);
  792.     char* const tmp_title = (titles ? titles[from] : 0);
  793.     MiscTableCellStyle tmp_style = (styles ? styles[from] : def_style);
  794.     id tmp_prototype = (prototypes ? prototypes[from] : 0);
  795.     MiscCompareEntryFunc const tmp_func = (sort_funcs ? sort_funcs[from] : 0);
  796.     MiscSortDirection tmp_dir =
  797.         (sort_dirs ? sort_dirs[from] : MISC_SORT_ASCENDING);
  798.     MiscSortType tmp_type =
  799.         (sort_types ? sort_types[from] : MISC_SORT_STRING_CASE_INSENSITIVE);
  800.  
  801.     if (p2v == 0)
  802.         alloc_vmap();
  803.  
  804.     do_shift( from, to );
  805.  
  806.     if (from < to)
  807.         {
  808.         for (int i = 0;     i < num_slots;     i++)
  809.             if (from < p2v[i] && p2v[i] <= to)
  810.                 p2v[i]--;
  811.         if (!was_cursor && from <= cursor && cursor >= to)
  812.             cursor--;
  813.         }
  814.     else
  815.         {
  816.         for (int i = 0;     i < num_slots;     i++)
  817.             if (to <= p2v[i] && p2v[i] < from)
  818.                 p2v[i]++;
  819.         if (!was_cursor && from <= cursor && cursor >= to)
  820.             cursor++;
  821.         }
  822.     p2v[p] = to;
  823.     v2p[to] = p;
  824.  
  825.     if (slots != 0)         slots[to]    = tmp_slot;
  826.     if (tags != 0)         tags[to]    = tmp_tag;
  827.     if (titles != 0)     titles[to] = tmp_title;
  828.     if (styles != 0)     styles[to] = tmp_style;
  829.     if (prototypes != 0) prototypes[to] = tmp_prototype;
  830.     if (sort_funcs != 0) sort_funcs[to] = tmp_func;
  831.     if (sort_dirs != 0)     sort_dirs[to]    = tmp_dir;
  832.     if (sort_types != 0) sort_types[to] = tmp_type;
  833.  
  834.     selection.shiftUpAt( to );
  835.     if (was_selected)
  836.         selection.add( to );
  837.     if (was_cursor)
  838.         cursor = to;
  839.     }
  840.  
  841.  
  842. //-----------------------------------------------------------------------------
  843. // setCount
  844. //-----------------------------------------------------------------------------
  845. void MiscTableBorder::setCount( int x )
  846.     {
  847.     setVMap(0);
  848.     if (num_slots != x)
  849.         {
  850.         needs_recalc = true;
  851.         int const old_slots = num_slots;
  852.         num_slots = x;
  853.         setCapacity( x );        // Only increases capacity, never decreases.
  854.  
  855.         if (old_slots < num_slots)
  856.             {
  857.             for (int i = old_slots;     i < num_slots;     i++)
  858.                 init_slot( i, i );
  859.             }
  860.         else
  861.             {
  862.             assert( old_slots <= max_slots );
  863.             num_slots = old_slots;
  864.             for (int i = x;     i < old_slots;     i++)
  865.                 destroy_slot( i );
  866.             num_slots = x;
  867.  
  868.             selection.remove( num_slots, old_slots );
  869.             if (cursor >= num_slots) selectNone();
  870.             }
  871.         }
  872.     }
  873.  
  874.  
  875. //-----------------------------------------------------------------------------
  876. // good_int_map
  877. //        'map' is a good map if all the values are in-range, and no value
  878. //        is repeated.  A null map represents a normal sequential series.
  879. //-----------------------------------------------------------------------------
  880. bool MiscTableBorder::good_int_map( int const* map ) const
  881.     {
  882.     bool answer = true;
  883.     int const lim = count();
  884.     if (lim > 0)
  885.         {
  886.         if (map != 0)
  887.             {
  888.             bool* seen = (bool*) calloc( sizeof(bool), lim );
  889.             for (int i = 0;     i < lim;  i++)
  890.                 {
  891.                 int const x = map[i];
  892.                 if ((unsigned int) x < (unsigned int)lim && !seen[i])
  893.                     seen[i] = true;
  894.                 else
  895.                     {
  896.                     answer = false;
  897.                     break;
  898.                     }
  899.                 }
  900.             free( seen );
  901.             }
  902.         }
  903.     return answer;
  904.     }
  905.  
  906.  
  907. //-----------------------------------------------------------------------------
  908. // goodVMap
  909. //-----------------------------------------------------------------------------
  910. bool MiscTableBorder::goodVMap( MiscCoord_V const* map ) const
  911.     {
  912.     return good_int_map( (int const*) map );
  913.     }
  914.  
  915.  
  916. //-----------------------------------------------------------------------------
  917. // goodPMap
  918. //-----------------------------------------------------------------------------
  919. bool MiscTableBorder::goodPMap( MiscCoord_P const* map ) const
  920.     {
  921.     return good_int_map( (int const*) map );
  922.     }
  923.  
  924.  
  925. //-----------------------------------------------------------------------------
  926. // do_remap
  927. //-----------------------------------------------------------------------------
  928. void* MiscTableBorder::do_remap( void* p, int n, MiscCoord_V const* new_p2v )
  929.     {
  930.     if (p != 0)
  931.         {
  932.         void* t = do_alloc( n );
  933.         for (int i = 0;     i < num_slots;     i++)
  934.             memcpy( t + MISC_MAP(new_p2v,i) * n,
  935.                         p + MISC_MAP(p2v,i) * n, n );
  936.         free( p );
  937.         p = t;
  938.         }
  939.     return p;
  940.     }
  941.  
  942.  
  943. //-----------------------------------------------------------------------------
  944. // do_remap
  945. //-----------------------------------------------------------------------------
  946. void MiscTableBorder::do_remap( MiscCoord_V const* new_p2v )
  947.     {
  948.     if (num_slots > 0)
  949.         {
  950.         slots = (MiscTableSlot*)
  951.                 do_remap( slots, sizeof(*slots), new_p2v );
  952.         tags = (int*)
  953.                 do_remap( tags, sizeof(*tags), new_p2v );
  954.         titles = (char**)
  955.                 do_remap( titles, sizeof(*titles), new_p2v );
  956.         styles = (MiscTableCellStyle*)
  957.                 do_remap( styles, sizeof(*styles), new_p2v );
  958.         prototypes = (id*)
  959.                 do_remap( prototypes, sizeof(*prototypes), new_p2v );
  960.         sort_funcs = (MiscCompareEntryFunc*)
  961.                 do_remap( sort_funcs, sizeof(*sort_funcs), new_p2v );
  962.         sort_dirs = (MiscSortDirection*)
  963.                 do_remap( sort_dirs, sizeof(*sort_dirs), new_p2v );
  964.         sort_types = (MiscSortType*)
  965.                 do_remap( sort_types, sizeof(*sort_types), new_p2v );
  966.         }
  967.     }
  968.  
  969.  
  970. //-----------------------------------------------------------------------------
  971. // setVMap
  972. //-----------------------------------------------------------------------------
  973. bool MiscTableBorder::setVMap( MiscCoord_V const* new_p2v )
  974.     {
  975.     if (goodVMap( new_p2v ))
  976.         {
  977.         if (new_p2v != 0 || p2v != 0)
  978.             {
  979.             needs_recalc = true;
  980.             do_remap( new_p2v );
  981.             if (p2v == 0)
  982.                 {
  983.                 p2v = (MiscCoord_V*) do_alloc( sizeof(*p2v) );
  984.                 v2p = (MiscCoord_P*) do_alloc( sizeof(*v2p) );
  985.                 }
  986.             if (new_p2v != 0 && p2v != 0)
  987.                 {
  988.                 for (int i = 0;     i < num_slots;     i++)
  989.                     v2p[new_p2v[i]] = i;
  990.                 memcpy( p2v, new_p2v, num_slots * sizeof(*p2v) );
  991.                 }
  992.             else if (new_p2v == 0)
  993.                 {
  994.                 free( p2v );  p2v = 0;
  995.                 free( v2p );  v2p = 0;
  996.                 }
  997.             }
  998.         return true;
  999.         }
  1000.     return false;
  1001.     }
  1002.  
  1003.  
  1004. //-----------------------------------------------------------------------------
  1005. // setPMap
  1006. //-----------------------------------------------------------------------------
  1007. bool MiscTableBorder::setPMap( MiscCoord_P const* new_v2p )
  1008.     {
  1009.     if (goodPMap( new_v2p ))
  1010.         {
  1011.         if (new_v2p != 0 || v2p != 0)
  1012.             {
  1013.             if (new_v2p != 0)
  1014.                 {
  1015.                 MiscCoord_V* new_p2v =
  1016.                         (MiscCoord_V*) malloc( sizeof(*new_p2v) * num_slots );
  1017.                 for (int i = 0;     i < num_slots;     i++)
  1018.                     new_p2v[new_v2p[i]] = i;
  1019.                 setVMap( new_p2v );
  1020.                 free( new_p2v );
  1021.                 }
  1022.             else
  1023.                 setVMap( 0 );
  1024.             }
  1025.         return true;
  1026.         }
  1027.     return false;
  1028.     }
  1029.  
  1030.  
  1031. //-----------------------------------------------------------------------------
  1032. // clearVMap
  1033. //-----------------------------------------------------------------------------
  1034. void MiscTableBorder::clearVMap()
  1035.     {
  1036.     if (v2p != 0) { free( v2p ); v2p = 0; }
  1037.     if (p2v != 0) { free( p2v ); p2v = 0; }
  1038.     }
  1039.  
  1040.  
  1041.  
  1042. //-----------------------------------------------------------------------------
  1043. // setUniformSize
  1044. //-----------------------------------------------------------------------------
  1045. bool MiscTableBorder::setUniformSize( MiscPixels x )
  1046.     {
  1047.     bool const changed = (uniform_size != x);
  1048.     if (changed)
  1049.         {
  1050.         needs_recalc = true;
  1051.         if (uniform_size == 0)    // New, non-zero uniform size.
  1052.             {
  1053.             if (slots != 0)
  1054.                 { free( slots );  slots = 0; }
  1055.             min_total_size = 0;
  1056.             max_total_size = MISC_MAX_PIXELS_SIZE;
  1057.             }
  1058.         uniform_size = x;
  1059.         }
  1060.     return changed;
  1061.     }
  1062.  
  1063.  
  1064.  
  1065. //-----------------------------------------------------------------------------
  1066. // setTitleMode
  1067. //-----------------------------------------------------------------------------
  1068. bool MiscTableBorder::setTitleMode( MiscTableTitleMode x )
  1069.     {
  1070.     MISC_ENUM_CHECK( x, MISC_MAX_TITLE );
  1071.     bool const changed = (title_mode != x);
  1072.     if (changed)
  1073.         {
  1074.         dealloc_titles();
  1075.         title_mode = x;
  1076.         }
  1077.     return changed;
  1078.     }
  1079.  
  1080.  
  1081.  
  1082. //-----------------------------------------------------------------------------
  1083. // totalSize
  1084. //-----------------------------------------------------------------------------
  1085. MiscPixels MiscTableBorder::totalSize()
  1086.     {
  1087.     if (num_slots == 0)
  1088.         return 0;
  1089.     else if (uniform_size)
  1090.         return (uniform_size * num_slots);
  1091.     else
  1092.         {
  1093.         recalc_if_needed();
  1094.         return getOffset( num_slots - 1 ) + effectiveSize( num_slots - 1 );
  1095.         }
  1096.     }
  1097.  
  1098.  
  1099. //-----------------------------------------------------------------------------
  1100. // setMinTotalSize
  1101. //-----------------------------------------------------------------------------
  1102. void MiscTableBorder::setMinTotalSize( MiscPixels x )
  1103.     {
  1104.     if (min_total_size != x)
  1105.         {
  1106.         needs_recalc = true;
  1107.         min_total_size = x;
  1108.         if (max_total_size < min_total_size)
  1109.             max_total_size = min_total_size;
  1110.         assert( 0 <= min_total_size );
  1111.         assert( min_total_size <= max_total_size );
  1112.         }
  1113.     }
  1114.  
  1115.  
  1116. //-----------------------------------------------------------------------------
  1117. // setMaxTotalSize
  1118. //-----------------------------------------------------------------------------
  1119. void MiscTableBorder::setMaxTotalSize( MiscPixels x )
  1120.     {
  1121.     if (max_total_size != x)
  1122.         {
  1123.         needs_recalc = true;
  1124.         max_total_size = x;
  1125.         if (min_total_size > max_total_size)
  1126.             min_total_size = max_total_size;
  1127.         assert( min_total_size <= max_total_size );
  1128.         assert( max_total_size <= MISC_MAX_PIXELS_SIZE );
  1129.         }
  1130.     }
  1131.  
  1132.  
  1133.  
  1134. //-----------------------------------------------------------------------------
  1135. // find_slot_for_offset
  1136. //-----------------------------------------------------------------------------
  1137. MiscCoord_V MiscTableBorder::find_slot_for_offset( MiscPixels x )
  1138.     {
  1139.     assert( num_slots > 0 );
  1140.     int lo = 0;
  1141.     int hi = num_slots - 1;
  1142.     while (lo <= hi)
  1143.         {
  1144.         int const mid = (lo + hi) >> 1;
  1145.         if (slots[mid].offset <= x)
  1146.             lo = mid + 1;
  1147.         else
  1148.             hi = mid - 1;
  1149.         }
  1150.     if (lo > 0 && (lo >= num_slots || slots[lo].offset > x))
  1151.         lo--;
  1152.     return lo;
  1153.     }
  1154.  
  1155.  
  1156. //-----------------------------------------------------------------------------
  1157. // visualForOffset
  1158. //-----------------------------------------------------------------------------
  1159. MiscCoord_V MiscTableBorder::visualForOffset( MiscPixels x )
  1160.     {
  1161.     MiscCoord_V i = -1;
  1162.     if (x >= 0 && num_slots > 0)
  1163.         {
  1164.         if (uniform_size != 0)
  1165.             {
  1166.             i = (MiscCoord_V) (x / uniform_size);
  1167.             }
  1168.         else
  1169.             {
  1170.             recalc_if_needed();
  1171.             i = find_slot_for_offset( x );
  1172.             }
  1173.         }
  1174.     if (i >= num_slots)
  1175.         i = num_slots - 1;
  1176.     return i;
  1177.     }
  1178.  
  1179.  
  1180. //-----------------------------------------------------------------------------
  1181. // getOffset
  1182. //-----------------------------------------------------------------------------
  1183. MiscPixels MiscTableBorder::getOffset( MiscCoord_V x )
  1184.     {
  1185.     if (num_slots == 0)
  1186.         return 0;
  1187.     MISC_RANGE_CHECK( x );
  1188.     if (uniform_size != 0)
  1189.         return uniform_size * x;
  1190.     recalc_if_needed();
  1191.     return MISC_SLOT_MEMBER( x, offset );
  1192.     }
  1193.  
  1194.  
  1195. //-----------------------------------------------------------------------------
  1196. // getSize
  1197. //-----------------------------------------------------------------------------
  1198. MiscPixels MiscTableBorder::getSize( MiscCoord_V x ) const
  1199.     {
  1200.     if (num_slots == 0)
  1201.         return 0;
  1202.     MISC_RANGE_CHECK( x );
  1203.     if (uniform_size != 0)
  1204.         return uniform_size;
  1205.     return MISC_SLOT_MEMBER( x, size );
  1206.     }
  1207.  
  1208.  
  1209. //-----------------------------------------------------------------------------
  1210. // getMinSize
  1211. //-----------------------------------------------------------------------------
  1212. MiscPixels MiscTableBorder::getMinSize( MiscCoord_V x ) const
  1213.     {
  1214.     MISC_RANGE_CHECK( x );
  1215.     if (uniform_size != 0)
  1216.         return uniform_size;
  1217.     return MISC_SLOT_MEMBER( x, min_size );
  1218.     }
  1219.  
  1220.  
  1221. //-----------------------------------------------------------------------------
  1222. // getMaxSize
  1223. //-----------------------------------------------------------------------------
  1224. MiscPixels MiscTableBorder::getMaxSize( MiscCoord_V x ) const
  1225.     {
  1226.     MISC_RANGE_CHECK( x );
  1227.     if (uniform_size != 0)
  1228.         return uniform_size;
  1229.     return MISC_SLOT_MEMBER( x, max_size );
  1230.     }
  1231.  
  1232.  
  1233. //-----------------------------------------------------------------------------
  1234. // getDataSize
  1235. //-----------------------------------------------------------------------------
  1236. MiscPixels MiscTableBorder::getDataSize( MiscCoord_V x ) const
  1237.     {
  1238.     MISC_RANGE_CHECK( x );
  1239.     if (uniform_size != 0)
  1240.         return uniform_size;
  1241.     return MISC_SLOT_MEMBER( x, data_size );
  1242.     }
  1243.  
  1244.  
  1245. //-----------------------------------------------------------------------------
  1246. // effectiveSize
  1247. //-----------------------------------------------------------------------------
  1248. MiscPixels MiscTableBorder::effectiveSize( MiscCoord_V x )
  1249.     {
  1250.     MISC_RANGE_CHECK( x );
  1251.     if (uniform_size != 0)
  1252.         return uniform_size;
  1253.     recalc_if_needed();
  1254.     return MISC_SLOT_MEMBER( x, adj_size );
  1255.     }
  1256.  
  1257.  
  1258. //-----------------------------------------------------------------------------
  1259. // effectiveMaxSize
  1260. //-----------------------------------------------------------------------------
  1261. MiscPixels MiscTableBorder::effectiveMaxSize( MiscCoord_V x )
  1262.     {
  1263.     MISC_RANGE_CHECK( x );
  1264.     if (uniform_size != 0)
  1265.         return uniform_size;
  1266.  
  1267.     recalc_if_needed();
  1268.  
  1269.     MiscTableSlot const& r = slots[x];
  1270.     MiscPixels slot_max = r.max_size;
  1271.  
  1272.     MiscPixels global_max = max_total_size;
  1273.  
  1274.     for (int i = 0;     i < num_slots;     i++)
  1275.         {
  1276.         if (i != x)
  1277.             {
  1278.             MiscTableSlot& t = slots[i];
  1279.             if (t.isSpringy())
  1280.                 global_max -= t.min_size;
  1281.             else
  1282.                 global_max -= t.size;
  1283.             }
  1284.         }
  1285.  
  1286.     if (slot_max > global_max)
  1287.         slot_max = global_max;
  1288.  
  1289.     return slot_max;
  1290.     }
  1291.  
  1292.  
  1293. //-----------------------------------------------------------------------------
  1294. // effectiveMinSize
  1295. //-----------------------------------------------------------------------------
  1296. MiscPixels MiscTableBorder::effectiveMinSize( MiscCoord_V x )
  1297.     {
  1298.     MISC_RANGE_CHECK( x );
  1299.     if (uniform_size != 0)
  1300.         return uniform_size;
  1301.  
  1302.     recalc_if_needed();
  1303.  
  1304.     MiscTableSlot const& r = slots[x];
  1305.     MiscPixels slot_min = r.min_size;
  1306.  
  1307.     MiscPixels global_min = min_total_size;
  1308.  
  1309.     for (int i = 0;     i < num_slots;     i++)
  1310.         {
  1311.         if (i != x)
  1312.             {
  1313.             MiscTableSlot& t = slots[i];
  1314.             if (t.isSpringy())
  1315.                 global_min -= t.max_size;
  1316.             else
  1317.                 global_min -= t.size;
  1318.             }
  1319.         }
  1320.  
  1321.     if (slot_min < global_min)
  1322.         slot_min = global_min;
  1323.  
  1324.     if (slot_min > r.adj_size)
  1325.         slot_min = r.adj_size;
  1326.  
  1327.     return slot_min;
  1328.     }
  1329.  
  1330.  
  1331. //-----------------------------------------------------------------------------
  1332. // getSizing
  1333. //-----------------------------------------------------------------------------
  1334. MiscTableSizing MiscTableBorder::getSizing( MiscCoord_V x ) const
  1335.     {
  1336.     MISC_RANGE_CHECK( x );
  1337.     if (uniform_size != 0)
  1338.         return MISC_NUSER_NDATA_NSPRINGY_SIZING;
  1339.     return MISC_SLOT_MEMBER( x, sizing );
  1340.     }
  1341.  
  1342.  
  1343. //-----------------------------------------------------------------------------
  1344. // alpha_title
  1345. //-----------------------------------------------------------------------------
  1346. static char* alpha_title( char* p, int x )
  1347.     {
  1348.     *--p = '\0';
  1349.     if (x >= 26)
  1350.         {
  1351.         do    {
  1352.             *--p = (x % 26) + 'A';
  1353.             x /= 26;
  1354.             }
  1355.         while (x >= 26);
  1356.         x--;
  1357.         }
  1358.     *--p = x + 'A';
  1359.     return p;
  1360.     }
  1361.  
  1362.  
  1363. //-----------------------------------------------------------------------------
  1364. // getTitle
  1365. //-----------------------------------------------------------------------------
  1366. char const* MiscTableBorder::getTitle( MiscCoord_V x ) const
  1367.     {
  1368.     int const BUFF_LEN = 16;
  1369.     static char buff[ BUFF_LEN ];
  1370.     char const* s =     "";
  1371.     MISC_RANGE_CHECK( x );
  1372.     switch (title_mode)
  1373.         {
  1374.     case MISC_NO_TITLE:
  1375.                 break;
  1376.     case MISC_NUMBER_TITLE:
  1377.                 sprintf( buff, "%d", visualToPhysical(x) + 1 );
  1378.                 s = buff;
  1379.                 break;
  1380.     case MISC_ALPHA_TITLE:
  1381.                 s = alpha_title( buff + BUFF_LEN, visualToPhysical(x) );
  1382.                 break;
  1383.     case MISC_CUSTOM_TITLE:
  1384.                 s = (titles != 0) ? titles[x] : "";
  1385.                 break;
  1386.     case MISC_DELEGATE_TITLE:
  1387.                 s = get_title( x );
  1388.                 break;
  1389.         }
  1390.     return s;
  1391.     }
  1392.  
  1393.  
  1394. //-----------------------------------------------------------------------------
  1395. // getTag
  1396. //-----------------------------------------------------------------------------
  1397. int MiscTableBorder::getTag( MiscCoord_V x ) const
  1398.     {
  1399.     MISC_RANGE_CHECK( x );
  1400.     return (tags != 0) ? tags[x] : def_tag;
  1401.     }
  1402.  
  1403.  
  1404. //-----------------------------------------------------------------------------
  1405. // getStyle
  1406. //-----------------------------------------------------------------------------
  1407. MiscTableCellStyle MiscTableBorder::getStyle( MiscCoord_V x ) const
  1408.     {
  1409.     MISC_RANGE_CHECK( x );
  1410.     return (styles != 0) ? styles[x] : def_style;
  1411.     }
  1412.  
  1413.  
  1414. //-----------------------------------------------------------------------------
  1415. // getSortFunc
  1416. //-----------------------------------------------------------------------------
  1417. MiscCompareEntryFunc MiscTableBorder::getSortFunc( MiscCoord_V x ) const
  1418.     {
  1419.     MISC_RANGE_CHECK( x );
  1420.     return (sort_funcs != 0) ? sort_funcs[x] : 0;
  1421.     }
  1422.  
  1423.  
  1424. //-----------------------------------------------------------------------------
  1425. // getSortDirection
  1426. //-----------------------------------------------------------------------------
  1427. MiscSortDirection MiscTableBorder::getSortDirection( MiscCoord_V x ) const
  1428.     {
  1429.     MISC_RANGE_CHECK( x );
  1430.     return (sort_dirs != 0) ? sort_dirs[x] : MISC_SORT_ASCENDING;
  1431.     }
  1432.  
  1433.  
  1434. //-----------------------------------------------------------------------------
  1435. // getSortType
  1436. //-----------------------------------------------------------------------------
  1437. MiscSortType MiscTableBorder::getSortType( MiscCoord_V x ) const
  1438.     {
  1439.     MISC_RANGE_CHECK( x );
  1440.     return (sort_types != 0) ? sort_types[x] :
  1441.                                 MISC_SORT_STRING_CASE_INSENSITIVE;
  1442.     }
  1443.  
  1444.  
  1445. //-----------------------------------------------------------------------------
  1446. // alloc_prototypes
  1447. //-----------------------------------------------------------------------------
  1448. void MiscTableBorder::alloc_prototypes()
  1449.     {
  1450.     prototypes = (id*) do_alloc_init( sizeof(*prototypes) );
  1451.     }
  1452.  
  1453.  
  1454. //-----------------------------------------------------------------------------
  1455. // new_prototype
  1456. //-----------------------------------------------------------------------------
  1457. id MiscTableBorder::new_prototype( MiscCoord_V x )
  1458.     {
  1459.     NXZone* const zone = [owner zone];
  1460.     id p = 0;
  1461.     switch (getStyle(x))
  1462.         {
  1463.         case MISC_TABLE_CELL_TEXT:
  1464.                 p = [[MiscTableCell allocFromZone:zone] initTextCell:0];
  1465.                 break;
  1466.         case MISC_TABLE_CELL_ICON:
  1467.                 p = [[MiscTableCell allocFromZone:zone] initIconCell:0];
  1468.                 break;
  1469.         case MISC_TABLE_CELL_BUTTON:
  1470.                 p = [[ButtonCell allocFromZone:zone] initTextCell:0];
  1471.                 break;
  1472.         case MISC_TABLE_CELL_CALLBACK:
  1473.                 p = get_prototype(x);
  1474.                 break;
  1475.         }
  1476.     return p;
  1477.     }
  1478.  
  1479.  
  1480. //-----------------------------------------------------------------------------
  1481. // getPrototype
  1482. //-----------------------------------------------------------------------------
  1483. id MiscTableBorder::getPrototype( MiscCoord_V x )
  1484.     {
  1485.     MISC_RANGE_CHECK( x );
  1486.     if (prototypes == 0)
  1487.         alloc_prototypes();
  1488.     id p = prototypes[x];
  1489.     if (p == 0)
  1490.         p = prototypes[x] = new_prototype(x);
  1491.     return p;
  1492.     }
  1493.  
  1494.  
  1495.  
  1496. //-----------------------------------------------------------------------------
  1497. // alloc_slots
  1498. //-----------------------------------------------------------------------------
  1499. void MiscTableBorder::alloc_slots()
  1500.     {
  1501.     assert( slots == 0 );
  1502.     slots = (MiscTableSlot*) do_alloc( sizeof(*slots) );
  1503.     for (int i = 0;     i < num_slots;     i++)
  1504.         slots[i] = def_slot;
  1505.     }
  1506.  
  1507.  
  1508. //-----------------------------------------------------------------------------
  1509. // setSize
  1510. //-----------------------------------------------------------------------------
  1511. void MiscTableBorder::setSize( MiscCoord_V x, MiscPixels n )
  1512.     {
  1513.     MISC_RANGE_CHECK( x );
  1514.     if (uniform_size == 0)
  1515.         MISC_SET_SLOT_MEMBER( x, n, size );
  1516.     }
  1517.  
  1518.  
  1519. //-----------------------------------------------------------------------------
  1520. // setMinSize
  1521. //-----------------------------------------------------------------------------
  1522. void MiscTableBorder::setMinSize( MiscCoord_V x, MiscPixels n )
  1523.     {
  1524.     MISC_RANGE_CHECK( x );
  1525.     if (uniform_size == 0)
  1526.         MISC_SET_SLOT_MEMBER( x, n, min_size );
  1527.     }
  1528.  
  1529.  
  1530. //-----------------------------------------------------------------------------
  1531. // setMaxSize
  1532. //-----------------------------------------------------------------------------
  1533. void MiscTableBorder::setMaxSize( MiscCoord_V x, MiscPixels n )
  1534.     {
  1535.     MISC_RANGE_CHECK( x );
  1536.     if (uniform_size == 0)
  1537.         MISC_SET_SLOT_MEMBER( x, n, max_size );
  1538.     }
  1539.  
  1540.  
  1541. //-----------------------------------------------------------------------------
  1542. // setDataSize
  1543. //-----------------------------------------------------------------------------
  1544. void MiscTableBorder::setDataSize( MiscCoord_V x, MiscPixels n )
  1545.     {
  1546.     MISC_RANGE_CHECK( x );
  1547.     if (uniform_size == 0)
  1548.         MISC_SET_SLOT_MEMBER( x, n, data_size );
  1549.     }
  1550.  
  1551.  
  1552. //-----------------------------------------------------------------------------
  1553. // setSizing
  1554. //-----------------------------------------------------------------------------
  1555. void MiscTableBorder::setSizing( MiscCoord_V x, MiscTableSizing n )
  1556.     {
  1557.     MISC_RANGE_CHECK( x );
  1558.     MISC_ENUM_CHECK( n, MISC_MAX_SIZING );
  1559.     if (uniform_size == 0)
  1560.         {
  1561.         bool was_springy = ::isSpringy(getSizing(x));
  1562.         bool is_springy = ::isSpringy(n);
  1563.         if (was_springy != is_springy)
  1564.             {
  1565.             if (was_springy)
  1566.                 num_springy--;
  1567.             else
  1568.                 num_springy++;
  1569.             }
  1570.         MISC_SET_SLOT_MEMBER( x, n, sizing );
  1571.         }
  1572.     }
  1573.  
  1574.  
  1575.  
  1576. //-----------------------------------------------------------------------------
  1577. // dealloc_titles
  1578. //-----------------------------------------------------------------------------
  1579. void MiscTableBorder::dealloc_titles()
  1580.     {
  1581.     if (titles != 0)
  1582.         {
  1583.         for (int i = 0;     i < num_slots;     i++)
  1584.             if (titles[i] != 0)
  1585.                 free( titles[i] );
  1586.         free( titles );
  1587.         titles = 0;
  1588.         }
  1589.     }
  1590.  
  1591.  
  1592.  
  1593. //-----------------------------------------------------------------------------
  1594. // alloc_titles
  1595. //-----------------------------------------------------------------------------
  1596. void MiscTableBorder::alloc_titles()
  1597.     {
  1598.     titles = (char**) do_alloc_init( sizeof(*titles) );
  1599.     }
  1600.  
  1601.  
  1602. //-----------------------------------------------------------------------------
  1603. // do_strdup
  1604. //-----------------------------------------------------------------------------
  1605. static char* do_strdup( char const* s )
  1606.     {
  1607.     char* p = 0;
  1608.     if (s != 0 && *s != 0)
  1609.         strcpy( p = (char*) malloc( strlen(s) + 1 ), s );
  1610.     return p;
  1611.     }
  1612.  
  1613.  
  1614. //-----------------------------------------------------------------------------
  1615. // setTitle
  1616. //-----------------------------------------------------------------------------
  1617. bool MiscTableBorder::setTitle( MiscCoord_V x, char const* s )
  1618.     {
  1619.     bool changed = false;
  1620.     if (getTitleMode() == MISC_CUSTOM_TITLE)
  1621.         {
  1622.         MISC_RANGE_CHECK( x );
  1623.         char* const t = (titles ? titles[x] : 0);
  1624.         if (t != 0 || s != 0)
  1625.             {
  1626.             if (t == 0 || s == 0 || strcmp(t,s) != 0)
  1627.                 {
  1628.                 if (t != 0) free(t);
  1629.                 if (titles == 0) alloc_titles();
  1630.                 titles[x] = do_strdup(s);
  1631.                 changed = true;
  1632.                 }
  1633.             }
  1634.         }
  1635.     return changed;
  1636.     }
  1637.  
  1638.  
  1639. //-----------------------------------------------------------------------------
  1640. // alloc_tags
  1641. //-----------------------------------------------------------------------------
  1642. void MiscTableBorder::alloc_tags()
  1643.     {
  1644.     tags = (int*) do_alloc_init( sizeof(*tags) );
  1645.     if (def_tag != 0)
  1646.         for (int i = 0;     i < num_slots;     i++)
  1647.             tags[i] = def_tag;
  1648.     }
  1649.  
  1650.  
  1651. //-----------------------------------------------------------------------------
  1652. // setTag
  1653. //-----------------------------------------------------------------------------
  1654. void MiscTableBorder::setTag( MiscCoord_V x, int n )
  1655.     {
  1656.     MISC_RANGE_CHECK( x );
  1657.     if (tags == 0) alloc_tags();
  1658.     tags[x] = n;
  1659.     }
  1660.  
  1661.  
  1662. //-----------------------------------------------------------------------------
  1663. // alloc_styles
  1664. //-----------------------------------------------------------------------------
  1665. void MiscTableBorder::alloc_styles()
  1666.     {
  1667.     styles = (MiscTableCellStyle*) do_alloc_init( sizeof(*styles) );
  1668.     if ((int) def_style != 0)
  1669.         for (int i = 0;     i < num_slots;     i++)
  1670.             styles[i] = def_style;
  1671.     }
  1672.  
  1673.  
  1674. //-----------------------------------------------------------------------------
  1675. // setStyle
  1676. //-----------------------------------------------------------------------------
  1677. void MiscTableBorder::setStyle( MiscCoord_V x, MiscTableCellStyle n )
  1678.     {
  1679.     MISC_RANGE_CHECK( x );
  1680.     MISC_ENUM_CHECK( n, MISC_TABLE_CELL_MAX );
  1681.     if (styles == 0) alloc_styles();
  1682.     styles[x] = n;
  1683.     }
  1684.  
  1685.  
  1686. //-----------------------------------------------------------------------------
  1687. // setPrototype
  1688. //-----------------------------------------------------------------------------
  1689. void MiscTableBorder::setPrototype( MiscCoord_V x, id n )
  1690.     {
  1691.     MISC_RANGE_CHECK( x );
  1692.     if (prototypes == 0) alloc_prototypes();
  1693.     if (prototypes[x] != 0)
  1694.         [prototypes[x] free];
  1695.     prototypes[x] = n;
  1696.     }
  1697.  
  1698.  
  1699.  
  1700. //-----------------------------------------------------------------------------
  1701. // alloc_sort_funcs
  1702. //-----------------------------------------------------------------------------
  1703. void MiscTableBorder::alloc_sort_funcs()
  1704.     {
  1705.     sort_funcs = (MiscCompareEntryFunc*) do_alloc_init( sizeof(*sort_funcs) );
  1706.     }
  1707.  
  1708.  
  1709. //-----------------------------------------------------------------------------
  1710. // setSortFunc
  1711. //-----------------------------------------------------------------------------
  1712. void MiscTableBorder::setSortFunc( MiscCoord_V x, MiscCompareEntryFunc n )
  1713.     {
  1714.     MISC_RANGE_CHECK( x );
  1715.     if (sort_funcs == 0) alloc_sort_funcs();
  1716.     sort_funcs[x] = n;
  1717.     }
  1718.  
  1719.  
  1720.  
  1721. //-----------------------------------------------------------------------------
  1722. // alloc_sort_dirs
  1723. //-----------------------------------------------------------------------------
  1724. void MiscTableBorder::alloc_sort_dirs()
  1725.     {
  1726.     sort_dirs = (MiscSortDirection*) do_alloc_init( sizeof(*sort_dirs) );
  1727.     }
  1728.  
  1729.  
  1730. //-----------------------------------------------------------------------------
  1731. // setSortDirection
  1732. //-----------------------------------------------------------------------------
  1733. void MiscTableBorder::setSortDirection( MiscCoord_V x, MiscSortDirection n )
  1734.     {
  1735.     MISC_RANGE_CHECK( x );
  1736.     MISC_ENUM_CHECK( n, MISC_SORT_DIR_MAX );
  1737.     if (sort_dirs == 0) alloc_sort_dirs();
  1738.     sort_dirs[x] = n;
  1739.     }
  1740.  
  1741.  
  1742.  
  1743. //-----------------------------------------------------------------------------
  1744. // alloc_sort_types
  1745. //-----------------------------------------------------------------------------
  1746. void MiscTableBorder::alloc_sort_types()
  1747.     {
  1748.     sort_types = (MiscSortType*) do_alloc_init( sizeof(*sort_types) );
  1749.     }
  1750.  
  1751.  
  1752. //-----------------------------------------------------------------------------
  1753. // setSortType
  1754. //-----------------------------------------------------------------------------
  1755. void MiscTableBorder::setSortType( MiscCoord_V x, MiscSortType n )
  1756.     {
  1757.     MISC_RANGE_CHECK( x );
  1758.     MISC_ENUM_CHECK( n, MISC_SORT_TYPE_MAX );
  1759.     if (sort_types == 0) alloc_sort_types();
  1760.     sort_types[x] = n;
  1761.     }
  1762.  
  1763.  
  1764. //-----------------------------------------------------------------------------
  1765. // isSlotSelected
  1766. //-----------------------------------------------------------------------------
  1767. bool MiscTableBorder::slotIsSelected( MiscCoord_P s ) const
  1768.     {
  1769.     return (s >= 0 && s < num_slots ?
  1770.                 selection.contains(physicalToVisual(s)) : false);
  1771.     }
  1772.  
  1773.  
  1774. //-----------------------------------------------------------------------------
  1775. // selectedSlot
  1776. //-----------------------------------------------------------------------------
  1777. MiscCoord_P MiscTableBorder::selectedSlot() const
  1778.     {
  1779.     MiscCoord_V const s = selection.getCursor();
  1780.     return (s >= 0 && s < num_slots ? visualToPhysical(s) : -1);
  1781.     }
  1782.  
  1783.  
  1784. //-----------------------------------------------------------------------------
  1785. // selectSlot
  1786. //-----------------------------------------------------------------------------
  1787. void MiscTableBorder::selectSlot( MiscCoord_P s )
  1788.     {
  1789.     MISC_RANGE_CHECK( s );
  1790.     selection.add( physicalToVisual(s) );
  1791.     }
  1792.  
  1793.  
  1794. //-----------------------------------------------------------------------------
  1795. // selectedSlots
  1796. //-----------------------------------------------------------------------------
  1797. bool MiscTableBorder::hasMultipleSelection() const
  1798.     {
  1799.     bool ret = false;
  1800.     if (hasSelection())
  1801.         {
  1802.         MiscCoord_V lo, hi;
  1803.         selection.getTotalRange( lo, hi );
  1804.         ret = (hi > lo);
  1805.         }
  1806.     return ret;
  1807.     }
  1808.  
  1809.  
  1810. //-----------------------------------------------------------------------------
  1811. // selectedSlots
  1812. //-----------------------------------------------------------------------------
  1813. void MiscTableBorder::selected_slots(MiscIntList* list, bool do_tags) const
  1814.     {
  1815.     [list empty];
  1816.     for (unsigned int i = 0, lim = selection.numRanges(); i < lim; i++)
  1817.         {
  1818.         MiscCoord_V lo, hi;
  1819.         selection.getRangeAt( i, lo, hi );
  1820.         for ( ; lo <= hi; lo++)
  1821.             [list addInt: (do_tags ? getTag(lo) : visualToPhysical(lo))];
  1822.         }
  1823.     }
  1824.  
  1825.  
  1826. //-----------------------------------------------------------------------------
  1827. // selectSlots
  1828. //-----------------------------------------------------------------------------
  1829. void MiscTableBorder::selectSlots( MiscIntList* list )
  1830.     {
  1831.     for (int i = [list count]; i-- > 0; )
  1832.         selection.add( physicalToVisual([list intAt:i]) );
  1833.     }
  1834.  
  1835.  
  1836. //-----------------------------------------------------------------------------
  1837. // selectTags
  1838. //        FIXME: Sort the incoming list and do binary instead of linear search.
  1839. //-----------------------------------------------------------------------------
  1840. void MiscTableBorder::selectTags( MiscIntList* list )
  1841.     {
  1842.     unsigned int const lim = [list count];
  1843.     if (lim > 0)
  1844.         {
  1845.         unsigned int i;
  1846.         int* inTags = (int*)malloc( lim * sizeof(int) );
  1847.         for (i = 0; i < lim; i++)
  1848.             inTags[i] = [list intAt:i];
  1849.  
  1850.         for (int j = count(); j-- > 0; )
  1851.             {
  1852.             int const t = getTag(j);            // MiscCoord_V
  1853.             for (i = lim; i-- > 0; )
  1854.                 {
  1855.                 if (t == inTags[i])
  1856.                     {
  1857.                     selection.add(j);            // MiscCoord_V
  1858.                     break;
  1859.                     }
  1860.                 }
  1861.             }
  1862.         free( inTags );
  1863.         }
  1864.     }
  1865.  
  1866.  
  1867.  
  1868. //-----------------------------------------------------------------------------
  1869. // MiscTableSlot::read
  1870. //-----------------------------------------------------------------------------
  1871. void MiscTableSlot::read( NXTypedStream* stream )
  1872.     {
  1873.     NXReadType( stream, @encode(MiscPixels), &size );
  1874.     NXReadType( stream, @encode(MiscPixels), &min_size );
  1875.     NXReadType( stream, @encode(MiscPixels), &max_size );
  1876.     NXReadType( stream, @encode(MiscPixels), &data_size );
  1877.     NXReadType( stream, @encode(MiscTableSizing), &sizing );
  1878.     MISC_ENUM_CHECK( sizing, MISC_MAX_SIZING );
  1879.     offset = 0;
  1880.     adj_size = size;
  1881.     }
  1882.  
  1883.  
  1884. //-----------------------------------------------------------------------------
  1885. // MiscTableSlot::write
  1886. //-----------------------------------------------------------------------------
  1887. void MiscTableSlot::write( NXTypedStream* stream )
  1888.     {
  1889.     NXWriteType( stream, @encode(MiscPixels), &size );
  1890.     NXWriteType( stream, @encode(MiscPixels), &min_size );
  1891.     NXWriteType( stream, @encode(MiscPixels), &max_size );
  1892.     NXWriteType( stream, @encode(MiscPixels), &data_size );
  1893.     NXWriteType( stream, @encode(MiscTableSizing), &sizing );
  1894.     }
  1895.  
  1896.  
  1897. //-----------------------------------------------------------------------------
  1898. // write
  1899. //-----------------------------------------------------------------------------
  1900. void MiscTableBorder::write( NXTypedStream* stream )
  1901.     {
  1902.     int zero = 0;
  1903.  
  1904.     NXWriteType( stream, @encode(MiscBorderType), &type );
  1905.     NXWriteObjectReference( stream, owner );
  1906.     def_slot.write( stream );
  1907.     NXWriteType( stream, @encode(int), &num_slots );
  1908.  
  1909.     if (slots != 0)
  1910.         {
  1911.         NXWriteType( stream, @encode(int), &num_slots );
  1912.         for (int i = 0;     i < num_slots;     i++)
  1913.             slots[i].write(stream);
  1914.         }
  1915.     else
  1916.         NXWriteType( stream, @encode(int), &zero );
  1917.  
  1918.     if (v2p != 0)
  1919.         {
  1920.         NXWriteType( stream, @encode(int), &num_slots );
  1921.         for (int i = 0;     i < num_slots;     i++)
  1922.             NXWriteType( stream, @encode(MiscCoord_P), &(v2p[i]) );
  1923.         for (int j = 0;     j < num_slots;     j++)
  1924.             NXWriteType( stream, @encode(MiscCoord_V), &(p2v[j]) );
  1925.         }
  1926.     else
  1927.         NXWriteType( stream, @encode(int), &zero );
  1928.  
  1929.     NXWriteType( stream, @encode(int), &def_tag );
  1930.     if (tags != 0)
  1931.         {
  1932.         NXWriteType( stream, @encode(int), &num_slots );
  1933.         for (int i = 0;     i < num_slots;     i++)
  1934.             NXWriteType( stream, @encode(int), &(tags[i]) );
  1935.         }
  1936.     else
  1937.         NXWriteType( stream, @encode(int), &zero );
  1938.  
  1939.     NXWriteType( stream, @encode(MiscPixels), &uniform_size );
  1940.     NXWriteType( stream, @encode(MiscPixels), &min_total_size );
  1941.     NXWriteType( stream, @encode(MiscPixels), &max_total_size );
  1942.     NXWriteType( stream, @encode(int), &num_springy );
  1943.     NXWriteType( stream, @encode(MiscTableTitleMode), &title_mode );
  1944.  
  1945.     if (titles != 0)
  1946.         {
  1947.         NXWriteType( stream, @encode(int), &num_slots );
  1948.         for (int i = 0;     i < num_slots;     i++)
  1949.             NXWriteType( stream, @encode(char*), &(titles[i]) );
  1950.         }
  1951.     else
  1952.         NXWriteType( stream, @encode(int), &zero );
  1953.  
  1954.     NXWriteType( stream, @encode(MiscTableCellStyle), &def_style );
  1955.     if (styles != 0)
  1956.         {
  1957.         NXWriteType( stream, @encode(int), &num_slots );
  1958.         for (int i = 0;     i < num_slots;     i++)
  1959.             NXWriteType( stream, @encode(MiscTableCellStyle), &(styles[i]) );
  1960.         }
  1961.     else
  1962.         NXWriteType( stream, @encode(int), &zero );
  1963.  
  1964.     // Cannot archive sort_funcs -- it's the address of a function.
  1965.  
  1966.     if (prototypes != 0)
  1967.         {
  1968.         NXWriteType( stream, @encode(int), &num_slots );
  1969.         for (int i = 0;     i < num_slots;     i++)
  1970.             NXWriteObject( stream, prototypes[i] );
  1971.         }
  1972.     else
  1973.         NXWriteType( stream, @encode(int), &zero );
  1974.  
  1975.     if (sort_dirs != 0)
  1976.         {
  1977.         NXWriteType( stream, @encode(int), &num_slots );
  1978.         for (int i = 0;     i < num_slots;     i++)
  1979.             NXWriteType( stream, @encode(MiscSortDirection), &(sort_dirs[i]) );
  1980.         }
  1981.     else
  1982.         NXWriteType( stream, @encode(int), &zero );
  1983.  
  1984.     if (sort_types != 0)
  1985.         {
  1986.         NXWriteType( stream, @encode(int), &num_slots );
  1987.         for (int i = 0;     i < num_slots;     i++)
  1988.             NXWriteType( stream, @encode(MiscSortType), &(sort_types[i]) );
  1989.         }
  1990.     else
  1991.         NXWriteType( stream, @encode(int), &zero );
  1992.  
  1993.     NXWriteType( stream, @encode(bool), &selectable );
  1994.     NXWriteType( stream, @encode(bool), &sizeable );
  1995.     NXWriteType( stream, @encode(bool), &draggable );
  1996.     NXWriteType( stream, @encode(bool), &modifier_drag );
  1997.  
  1998.     needs_recalc = true;
  1999.     }
  2000.  
  2001.  
  2002. //-----------------------------------------------------------------------------
  2003. // read
  2004. //-----------------------------------------------------------------------------
  2005. void MiscTableBorder::read( NXTypedStream* stream )
  2006.     {
  2007.     int n;
  2008.     emptyAndFree();
  2009.  
  2010.     NXReadType( stream, @encode(MiscBorderType), &type );
  2011.     MISC_ENUM_CHECK( type, MISC_MAX_BORDER );
  2012.     owner = NXReadObject( stream );
  2013.     def_slot.read( stream );
  2014.     NXReadType( stream, @encode(int), &num_slots );
  2015.     max_slots = num_slots;
  2016.  
  2017.     NXReadType( stream, @encode(int), &n );
  2018.     if (n != 0)
  2019.         {
  2020.         alloc_slots();
  2021.         for (int i = 0;     i < num_slots;     i++)
  2022.             slots[i].read(stream);
  2023.         }
  2024.  
  2025.     NXReadType( stream, @encode(int), &n );
  2026.     if (n != 0)
  2027.         {
  2028.         alloc_vmap();
  2029.         for (int i = 0;     i < num_slots;     i++)
  2030.             NXReadType( stream, @encode(MiscCoord_P), &(v2p[i]) );
  2031.         for (int j = 0;     j < num_slots;     j++)
  2032.             NXReadType( stream, @encode(MiscCoord_V), &(p2v[j]) );
  2033.         }
  2034.  
  2035.     NXReadType( stream, @encode(int), &def_tag );
  2036.     NXReadType( stream, @encode(int), &n );
  2037.     if (n != 0)
  2038.         {
  2039.         alloc_tags();
  2040.         for (int i = 0;     i < num_slots;     i++)
  2041.             NXReadType( stream, @encode(int), &(tags[i]) );
  2042.         }
  2043.  
  2044.     NXReadType( stream, @encode(MiscPixels), &uniform_size );
  2045.     NXReadType( stream, @encode(MiscPixels), &min_total_size );
  2046.     NXReadType( stream, @encode(MiscPixels), &max_total_size );
  2047.     NXReadType( stream, @encode(int), &num_springy );
  2048.     NXReadType( stream, @encode(MiscTableTitleMode), &title_mode );
  2049.     MISC_ENUM_CHECK( title_mode, MISC_MAX_TITLE );
  2050.  
  2051.     NXReadType( stream, @encode(int), &n );
  2052.     if (n != 0)
  2053.         {
  2054.         alloc_titles();
  2055.         for (int i = 0;     i < num_slots;     i++)
  2056.             NXReadType( stream, @encode(char*), &(titles[i]) );
  2057.         }
  2058.  
  2059.     NXReadType( stream, @encode(MiscTableCellStyle), &def_style );
  2060.     MISC_ENUM_CHECK( def_style, MISC_TABLE_CELL_MAX );
  2061.  
  2062.     NXReadType( stream, @encode(int), &n );
  2063.     if (n != 0)
  2064.         {
  2065.         alloc_styles();
  2066.         for (int i = 0;     i < num_slots;     i++)
  2067.             {
  2068.             NXReadType( stream, @encode(MiscTableCellStyle), &(styles[i]) );
  2069.             MISC_ENUM_CHECK( styles[i], MISC_TABLE_CELL_MAX );
  2070.             }
  2071.         }
  2072.  
  2073.     NXReadType( stream, @encode(int), &n );
  2074.     if (n != 0)
  2075.         {
  2076.         alloc_prototypes();
  2077.         for (int i = 0;     i < num_slots;     i++)
  2078.             prototypes[i] = NXReadObject(stream);
  2079.         }
  2080.  
  2081.     // Cannot archive sort_funcs, they are function addresses.
  2082.     sort_funcs = 0;
  2083.  
  2084.     NXReadType( stream, @encode(int), &n );
  2085.     if (n != 0)
  2086.         {
  2087.         alloc_sort_dirs();
  2088.         for (int i = 0;     i < num_slots;     i++)
  2089.             {
  2090.             NXReadType( stream, @encode(MiscSortDirection), &(sort_dirs[i]) );
  2091.             MISC_ENUM_CHECK( sort_dirs[i], MISC_SORT_DIR_MAX );
  2092.             }
  2093.         }
  2094.  
  2095.     NXReadType( stream, @encode(int), &n );
  2096.     if (n != 0)
  2097.         {
  2098.         alloc_sort_types();
  2099.         for (int i = 0;     i < num_slots;     i++)
  2100.             {
  2101.             NXReadType( stream, @encode(MiscSortType), &(sort_types[i]) );
  2102.             MISC_ENUM_CHECK( sort_types[i], MISC_SORT_TYPE_MAX );
  2103.             }
  2104.         }
  2105.  
  2106.     NXReadType( stream, @encode(bool), &selectable );
  2107.     NXReadType( stream, @encode(bool), &sizeable );
  2108.     NXReadType( stream, @encode(bool), &draggable );
  2109.     NXReadType( stream, @encode(bool), &modifier_drag );
  2110.     needs_recalc = true;
  2111.     }
  2112.  
  2113.  
  2114. //-----------------------------------------------------------------------------
  2115. // Constructor
  2116. //-----------------------------------------------------------------------------
  2117. MiscTableBorder::MiscTableBorder( MiscBorderType x )
  2118.     {
  2119.     MISC_ENUM_CHECK( x, MISC_MAX_BORDER );
  2120.     memset( this, 0, sizeof(*this) );
  2121.     type = x;
  2122.     max_total_size = MISC_MAX_PIXELS_SIZE;
  2123.     clearCursor();
  2124.  
  2125.     if (type == MISC_ROW_BORDER)
  2126.         {
  2127.         uniform_size    = 18;
  2128.         def_slot.offset = 0;
  2129.         def_slot.size    = uniform_size;
  2130.         def_slot.min_size = 10;
  2131.         def_slot.max_size = MISC_MAX_PIXELS_SIZE;
  2132.         def_slot.data_size = 0;
  2133.         def_slot.sizing = MISC_NUSER_NDATA_NSPRINGY_SIZING;
  2134.         title_mode        = MISC_NUMBER_TITLE;
  2135.         draggable        = false;
  2136.         modifier_drag    = true;
  2137.         sizeable        = false;
  2138.         selectable        = true;
  2139.         }
  2140.     else
  2141.         {
  2142.         def_slot.offset = 0;
  2143.         def_slot.size    = 80;
  2144.         def_slot.min_size = 10;
  2145.         def_slot.max_size = MISC_MAX_PIXELS_SIZE;
  2146.         def_slot.data_size = 0;
  2147.         def_slot.sizing = MISC_USER_NDATA_NSPRINGY_SIZING;
  2148.         uniform_size    = 0;
  2149.         title_mode        = MISC_CUSTOM_TITLE;
  2150.         draggable        = true;
  2151.         modifier_drag    = false;
  2152.         sizeable        = true;
  2153.         selectable        = false;
  2154.         }
  2155.     }
  2156.  
  2157.  
  2158.  
  2159. //-----------------------------------------------------------------------------
  2160. // Destructor
  2161. //-----------------------------------------------------------------------------
  2162. MiscTableBorder::~MiscTableBorder()
  2163.     {
  2164.     emptyAndFree();
  2165.     }
  2166.